#include <storage.hpp>

#define MOUNT_PATH "/flash"
#define FS_LABEL   "storage"

static Storage* s_Storage = nullptr;

Storage* Storage::Instance(void)
{
	if (s_Storage == nullptr)
	{
		s_Storage = new Storage();
	}
	return s_Storage;
}

Storage::Storage()
{
}

Storage::~Storage()
{
}

void Storage::Init(void)
{
#if defined(CONFIG_TAR4ESP32)
	InitializeNvs();
	InitializeFileSystem();
	GetFileSystemInfo();
#endif
}

#if defined(CONFIG_TAR4ESP32)
void Storage::InitializeFileSystem(void)
{
	m_MountConfig.max_files				 = 16;
	m_MountConfig.format_if_mount_failed = true;

	esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(MOUNT_PATH, FS_LABEL, &m_MountConfig, &m_WlHandle);
	if (err != ESP_OK)
	{
		LOG("Failed to mount FATFS (%s)\n", esp_err_to_name(err));
		LOG("Try to format FATFS (%s)\n", MOUNT_PATH);
		err = esp_vfs_fat_spiflash_format_rw_wl(MOUNT_PATH, FS_LABEL);
		if (err != ESP_OK)
		{
			LOG("Failed to format FATFS (%s)\n", esp_err_to_name(err));
			return;
		}
	}
}

void Storage::InitializeNvs(void)
{
	esp_err_t err = nvs_flash_init();
	if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
	{
		ESP_ERROR_CHECK(nvs_flash_erase());
		err = nvs_flash_init();
	}
	ESP_ERROR_CHECK(err);
}

void Storage::GetFileSystemInfo(void)
{
	uint64_t out_total_bytes = 0;
	uint64_t out_free_bytes	 = 0;
	esp_err_t err			 = esp_vfs_fat_info(MOUNT_PATH, &out_total_bytes, &out_free_bytes);
	if (err != ESP_OK)
	{
		LOG("Failed to get FATFS (%s) info\n", esp_err_to_name(err));
		return;
	}

	uint64_t total_kb = out_total_bytes / 1024;
	uint64_t free_kb  = out_free_bytes / 1024;

	if (free_kb <= 400)
	{
		LOG("/Flash storage is too small, format and remount it.");
		err = esp_vfs_fat_spiflash_unmount_rw_wl(MOUNT_PATH, m_WlHandle);
		if (err != ESP_OK)
		{
			LOG("Failed to umount %s\n", MOUNT_PATH);
			return;
		}

		err = esp_vfs_fat_spiflash_format_rw_wl(MOUNT_PATH, FS_LABEL);
		if (err != ESP_OK)
		{
			LOG("Failed to format FATFS (%s)\n", esp_err_to_name(err));
			return;
		}

		InitializeFileSystem();

		err = esp_vfs_fat_info(MOUNT_PATH, &out_total_bytes, &out_free_bytes);
		if (err != ESP_OK)
		{
			LOG("Failed to get FATFS (%s) info\n", esp_err_to_name(err));
			return;
		}

		total_kb = out_total_bytes / 1024;
		free_kb	 = out_free_bytes / 1024;
	}

	LOG("%s total %lldKB, free %lldKB\n", MOUNT_PATH, total_kb, free_kb);
}
#endif